#include <openssl/ssl.h>
#include <openssl/err.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>

#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <net/route.h>
#include "rpc_ssl.h"


void ssl_low_level_init()
{
	/* Init ssl library */
    	SSL_library_init();
	/* Load all algorithms */
	OpenSSL_add_all_algorithms();
	/* Load openssl wrong infor */
	SSL_load_error_strings();	
}

void rpc_ssl_ctx_init(SSL_CTX *rpc_ctx)
{
    	SSL_CTX *ctx = rpc_ctx;

	/* You can use v2 & v3 compatible mode, you can also 
	use v2 | v3 mode like : SSLv2_server_method(), 
	SSLv3_server_method */
	ctx = SSL_CTX_new(SSLv23_server_method());
	if(ctx == NULL){
		ERR_print_errors_fp(stdout);
		exit(1);
	}
	printf("rpc ssl ctx init success !\n");
}

int rpc_ssl_read(SSL *ssl,unsigned char *request, int request_len)
{
	int nbytes, pkt_len, offset = 0;
    	unsigned char buf[RPC_READ_BUF];
    	int first_flag = 1;

	if(request_len > RPC_READ_BUF) return -1;
	
	while (1)
	{
		memset(buf, 0, RPC_READ_BUF);
		/* Read raw data from socket */
		nbytes = SSL_read(ssl, buf, RPC_READ_BUF - 1);
		if (nbytes <= 0) return -1;
		
		/* length field of packet is in the first packet */
		if (first_flag == 1)
		{
			pkt_len = cli_rpc_get_pkt_len(buf);
			if (pkt_len > RPC_READ_BUF-1)
			{
				printf("\r\n cc packet length is too long \r\n");
			}
			first_flag = 0;
		}
		memcpy(request + offset, buf, nbytes);
		if (nbytes+offset != pkt_len)
		{
			offset += nbytes;
			continue;
		}
		else break;
	}
	return pkt_len;
}
int rpc_ssl_write(SSL *rpcSock, unsigned char * response,int responseLen)
{
	int wl,slice,resend = 0;
	if (responseLen < slice_size)
	{
		wl = SSL_write(rpcSock, response, responseLen);
		resend =0;
		while ((wl != responseLen) && (resend < RSEND_TIMES))
		{
			printf("resend : w1=%d,len =%d\r\n",wl,responseLen);
			taskDelay(2);
			if(wl < 0)
				wl =0;
			wl += SSL_write(rpcSock, &response[wl], responseLen-wl);
			resend++;
		}
		if(wl!=responseLen)
		{
			printf("send error : w1=%d,responseLen =%d\r\n",wl,responseLen);
		}
	}
	else
	{
		for(slice=0;slice<(int)(responseLen/slice_size);slice++)
		{
			wl = SSL_write(rpcSock,&response[slice*slice_size], slice_size);
			resend = 0;
			while ((wl != slice_size) && (resend < RSEND_TIMES))
			{
				printf("resend : wl=%d,len = 800\r\n",wl);
				taskDelay(2);
				if(wl < 0)
					wl =0;
				wl += SSL_write(rpcSock, &response[wl], slice_size-wl);
				resend++;
			}
			if(wl!=slice_size)
			{
				printf("send error : wl=%d,len =800\r\n",wl);
			}
			/*printf("cli SmisServSubmit write %d bytes\r\n",wl);*/
		}
		if ((responseLen-(slice*slice_size))>0)
		{
			wl = SSL_write(rpcSock,&response[slice*slice_size], responseLen-(slice*slice_size));
			resend = 0;
			while ((wl != (responseLen-(slice*slice_size))) && (resend < RSEND_TIMES))
			{
				printf("resend : wl=%d,len = %d\r\n",wl,responseLen-(slice*slice_size));
				taskDelay(2);
				if(wl < 0)
					wl =0;
				wl += SSL_write(rpcSock, &response[wl], responseLen-(slice*slice_size)-wl);
				resend++;
			}
			if(wl != (responseLen-(slice * slice_size)))
			{
				printf("send error : wl=%d,len = %d\r\n",wl,(responseLen-(slice*slice_size)));
			}
		}
	}
	return 0;
}

int ssl_client(int libIndex, unsigned short port,  int family)
{
	int list,i,rpc_fd;
	struct sockaddr_in serv_addr;
	
	ssl_low_level_init();

	rpc_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (rpc_fd < 0)
	{
		printf("\r\n func = %s line = %d Create socket failure !\r\n", __FUNCTION__, __LINE__);
		return -1;
	}
	printf("socket = %d\n", rpc_fd);
	memset(&serv_addr, 0, sizeof(struct sockaddr_in));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);
	serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	//printf("ip-address: %s\n", g_cc_ipaddr_list[i]);
	if(0 != connect(rpc_fd, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr)))
	{
		perror("socket");
		printf("\r\n func = %s line = %d Connection failure !\r\n", __FUNCTION__, __LINE__);
		close(rpc_fd);
		taskDelay(100);
	}
	else
	{
		return -1;
	}
	return 0;
}

#if SSL_MAIN_TEST
int main()
{
	
	return ssl_client(0, 3369, AF_INET);

}
#endif


